<!--
    This file is used to add preview of the `.slint` snippets in the generated rustdoc documentation.
    It can be injected via the `--html-in-header slint-docs-preview.html` option of rustdoc.
-->
<script type="module">

    //import * as slint from 'https://releases.slint.dev/0.x.0/wasm-interpreter/slint_wasm_interpreter.js';
    //const editor_url = "https://releases.slint.dev/0.x.0/editor/";
    import * as slint from 'https://snapshots.slint.dev/master/wasm-interpreter/slint_wasm_interpreter.js';
    const editor_url = "https://snapshots.slint.dev/master/editor/";
    // keep them alive
    var all_instances = new Array;

    async function render_or_error(source, div) {
        const canvas_id = 'canvas_' + Math.random().toString(36).substr(2, 9);
        const canvas = document.createElement("canvas");
        canvas.id = canvas_id;
        div.appendChild(canvas);

        const { component, error_string } = await slint.compile_from_string(source, "");
        if (error_string != "") {
            var text = document.createTextNode(error_string);
            var p = document.createElement('pre');
            p.appendChild(text);
            div.innerHTML = "<pre style='color: red; background-color:#fee; margin:0'>" + p.innerHTML + "</pre>";
        }
        if (component !== undefined) {
            const instance = await component.create(canvas_id);
            await instance.show();
            all_instances.push(instance);
        }
    }

    async function create_preview(element, source_code) {
        // Style the preview such that a flexbox lays out the source code box
        // (which should take up any spare space), followed by the preview canvas.
        // The latter may wrap into a new row on mobile. The edit/play buttons are
        // placed last by flexbox order attribute.
        const div = document.createElement("div");
        const sourceCodeBox = element.firstElementChild;
        element.style = "display: flex; flex-wrap: wrap;";
        sourceCodeBox.style = "flex-grow: 2";
        element.append(div);
        await render_or_error(source_code, div);
    }

    function should_show_automatic_preview(element) {
        // The `no-auto-preview` doesn't map directly to a dedicated class but it's mangled differently
        // between rustdoc and sphinx, so match fuzzy on the entire class list:
        return !element.className.includes("no-auto-preview");
    }

    async function create_click_to_play_and_edit_buttons(element) {
        const source = element.innerText;

        const link_section = document.createElement("div");
        // Ensure the link section is always last and on a row of its own in the flexbox.
        link_section.style = "order: 100; flex-basis: 100%;";
        element.append(link_section);

        const button_style = "text-decoration: none;"

        const edit_button = document.createElement("a");
        edit_button.style = button_style;
        edit_button.href = `${editor_url}?snippet=${encodeURIComponent(source)}`;
        edit_button.target = "_blank";
        edit_button.innerText = "Edit 📝";
        link_section.append(edit_button);

        if (should_show_automatic_preview(element)) {
            create_preview(element, source);
        } else {
            const play_button = document.createElement("a");
            play_button.style = button_style;
            play_button.innerText = "Preview ▶️";
            play_button.onclick = async () => {
                play_button.remove();
                create_preview(element, source);
            };

            link_section.prepend(play_button);
        }
    }

    async function run() {
        await slint.default();

        slint.run_event_loop();

        const selector = ["code.language-slint", ".rustdoc pre.language-slint", "div.highlight-slint div.highlight", "div.highlight-slint\\,no-auto-preview div.highlight"]
            .map((sel) => `${sel}:not([class*=slint\\,ignore]):not([class*=slint\\,no-preview])`).join(",");
        var elements = document.querySelectorAll(selector);
        for (var i = 0; i < elements.length; ++i) {
            await create_click_to_play_and_edit_buttons(elements[i]);
        }
    }
    run();

    // Included markdown files may have links to other markdown files, which may not have been
    // resolved by rustdoc. This helper locates such links and resolves them, assuming that each
    // .md file gets its own sub-directory with an index.html.
    function fix_markdown_links() {
        for (const anchor of document.querySelectorAll('a[href$=".md"], a[href*=".md#"]')) {
            const url = new URL(anchor.href);
            const dir_separator = Math.max(url.pathname.lastIndexOf("/"), 0);
            const base_name = url.pathname.slice(dir_separator + 1, -3);
            const base_path = url.pathname.slice(0, dir_separator);
            url.pathname = base_path + "/../" + base_name + "/index.html";
            anchor.setAttribute("href", url);
        }
    }
    fix_markdown_links()
</script>
